namespace mp3_utils
{

    enum
    {
        MPG_MD_STEREO=0,
        MPG_MD_JOINT_STEREO=1,
        MPG_MD_DUAL_CHANNEL=2,
        MPG_MD_MONO=3,
    };

    typedef t_uint8 byte;

    enum {MPEG_1, MPEG_2, MPEG_25};

    struct TMPEGFrameInfo
    {
        unsigned m_bytes;
        unsigned m_sample_rate;
        unsigned m_layer;
        unsigned m_mpegversion;
        unsigned m_channels;
        unsigned m_duration;
        unsigned m_channel_mode;
        bool m_crc;
    };


    bool ParseMPEGFrameHeader(TMPEGFrameInfo & p_info,const t_uint8 p_header[4]);
    bool ValidateFrameCRC(const t_uint8 * frameData, t_size frameSize);
    bool ValidateFrameCRC(const t_uint8 * frameData, t_size frameSize, TMPEGFrameInfo const & frameInfo);

    //! Assumes valid frame with CRC (frameInfo.m_crc set, frameInfo.m_bytes <= frameSize).
    t_uint16 ExtractFrameCRC(const t_uint8 * frameData, t_size frameSize, TMPEGFrameInfo const & frameInfo);
    //! Assumes valid frame with CRC (frameInfo.m_crc set, frameInfo.m_bytes <= frameSize).
    t_uint16 CalculateFrameCRC(const t_uint8 * frameData, t_size frameSize, TMPEGFrameInfo const & frameInfo);
    //! Assumes valid frame with CRC (frameInfo.m_crc set, frameInfo.m_bytes <= frameSize).
    void RecalculateFrameCRC(t_uint8 * frameData, t_size frameSize, TMPEGFrameInfo const & frameInfo);

    unsigned QueryMPEGFrameSize(const t_uint8 p_header[4]);
    bool IsSameStream(TMPEGFrameInfo const & p_frame1,TMPEGFrameInfo const & p_frame2);
};

class mp3header
{
    t_uint8 bytes[4];
public:

    inline void copy(const mp3header & src)
    {
        memcpy(bytes,src.bytes,4);
    }
    inline void copy_raw(const void * src)
    {
        memcpy(bytes,src,4);
    }

    inline mp3header(const mp3header & src)
    {
        copy(src);
    }
    inline mp3header() {}

    inline const mp3header & operator=(const mp3header & src)
    {
        copy(src);
        return *this;
    }

    inline void get_bytes(void * out)
    {
        memcpy(out,bytes,4);
    }
    inline unsigned get_frame_size() const
    {
        return mp3_utils::QueryMPEGFrameSize(bytes);
    }
    inline bool decode(mp3_utils::TMPEGFrameInfo & p_out)
    {
        return mp3_utils::ParseMPEGFrameHeader(p_out,bytes);
    }

    unsigned get_samples_per_frame();
};

static inline mp3header mp3header_from_buffer(const void * p_buffer)
{
    mp3header temp;
    temp.copy_raw(p_buffer);
    return temp;
}
